<?php

class Model {

	private $version = '';	   //mysql版本
	private $config = array();   //数据库配置数组 
	private $class;	   //当前类名
	public  $tablepre = '';	  //表前缀
	public  $db = '';	 //库名    
	public  $table = '';  //表名
	public  $primaryKey = 'id';  //表主键
	public  $tmpPrimaryKey = '';  //临时手动指定表表主键
	private $linkArr = array(); //数据库链接池
	private static $linkType = ''; //当前链接
	private $data = array();	 //中间数据容器
	private $condition = '';	//查询条件
	private $fields = array();   //字段信息
	private $sql = array();	  //sql集合，调试用
	private $rand = true;	  //是否随机选择从库
	private $server = '';	  //链接哪天数据库服务器
	private $tmpTable  = '';  //手动指定数据表

	//构造函数初始化

	public function __construct($options = array()) {
		//如果参数只是一个一般的字符串，则认为是实例化一个没有模型文件的Model
		if (is_string($options)) {
			$this->table = $options;
		}
		//如果参数是数组，则认为是数据库配置文件，为空则使用默认配置文件  
		$this->config = (is_array($options) && !empty($options)) ? $options : AppConfig::$dbParam;
		$this->init();
	}

	private function getLinkType ($sql) {
		if (strtolower(substr(trim($sql), 0, 6)) == 'select') {
			if ($this->server != '') {
				$linkType = $this->server;
			} else {
				$count = count($this->config['slave']);
				if ($count <= 0) {
					$linkType = 'master';
				} else {
					$rand = rand(1, $count);
					if ($this->rand) {
						$linkType = 'slave'.$rand;
					} else {
						$slaveArr = array_diff(array_keys($this->linkArr), array('master'));
						$linkType = count($slaveArr) > 0 ? $slaveArr[0] : 'slave'.$rand;
					}
				}
			}
		} else {
			$linkType = 'master';
		}
		self::$linkType = $linkType;
		return $linkType;
	}

	//链接数据库
	private function connect($sql) {
		$linkType = $this->getLinkType($sql);
		if (!isset($this->linkArr[self::$linkType]) || !is_resource($this->linkArr[self::$linkType])) {
			$dbConfig = self::$linkType == 'master' ? $this->config[$linkType] : $dbConfig = $this->config['slave'][$linkType];
			if ($this->config['dbPconnect']) {
				$link = @mysql_pconnect($dbConfig['dbHost'], $dbConfig['dbUser'], $dbConfig['dbPassword']);
			} else {
				$link = @mysql_connect($dbConfig['dbHost'], $dbConfig['dbUser'], $dbConfig['dbPassword'], true);
			}
			!$link && $this->errdie('Could not connect Mysql: ');

			$this->db = !empty($this->db) ? $this->db : $this->config['dbName'];
			$this->linkArr[self::$linkType] = $link;
			$serverinfo = $this->version();
			if ($serverinfo > '4.1' && $this->config['dbCharset']) {
				mysql_query("SET character_set_connection=" . $this->config['dbCharset'] . ",character_set_results=" . $this->config['dbCharset'] . ",character_set_client=binary", $link);
			}
			if ($serverinfo > '5.0') {
				mysql_set_charset("{$this->config['dbCharset']}", $link);
			}
			@mysql_select_db($this->db, $link) or $this->errdie('Cannot use database');
		}
		return $this->linkArr[self::$linkType];
	}

	public function master() {
		$this->server('master');
		return $this;
		
	}

	public function slave($slave = '') {
		$slave = $slave == '' ? 'slave1' : $slave;
		$this->server($slave);
		return $this;
	}

	private function server($server) {
		$this->server = $server;
		
	}

	public function table($tablename = '', $primaryKey = '') {
		$tablename  != '' && $this->tmpTable = $tablename;
		$primaryKey != '' && $this->tmpPrimaryKey = $primaryKey;
		return func_num_args() > 0 ? $this : ($this->tmpTable != '' ? $this->tmpTable : $this->table);
		
	}

	//表基本信息初始化
	protected function init() {
		$this->class = get_class($this);
		$this->table = !empty($this->table) ? $this->table : strtolower($this->class);
		$this->table = $this->tablepre . $this->table;
		$this->rand  = $this->config['rand'];
		return $this;
	}

	//设置属性值
	public function __set($name, $value) {
		$this->data['fields'][$name] = $value;
	}

	//获取属性值
	public function __get($name) {
		if (isset($this->data['fields'][$name])) {
			return($this->data['fields'][$name]);
		} else {
			return NULL;
		}
	}

	//字段信息处理
	private function implodefields($data) {
		if (!is_array($data)) {
			$data = array();
		}
		$this->fields = !empty($this->data['fields']) ? array_merge($this->data['fields'], $data) : $data;
		foreach ($this->fields as $key => $value) {
			$value = $this->filter($value);
			$fieldsNameValueStr[] = "`$key`='$value'";
			$fieldsNameStr[] = "`$key`";
			$fieldsValueStr[] = "'$value'";
		}
		return array($fieldsNameValueStr, $fieldsNameStr, $fieldsValueStr);
	}

	//条件判断组装
	private function condition($where = NULL) {
		$primaryKey = $this->tmpPrimaryKey != '' ? $this->tmpPrimaryKey : $this->primaryKey;
		if (is_numeric($where)) {
			$where = "`{$primaryKey}`='{$where}' LIMIT 1";
		} elseif (is_array($where)) {
			if (is_numeric($where[0])) {
				$where = "`{$primaryKey}` in (" . implode(',', $where) . ")";
			} else if (is_array($where) && is_string($where[0]) && is_array($where[1])) {
				foreach ($where[1] as $key => $value ) {
					$where[1][$key] = "'".$this->filter($value)."'";
				}
				$format = str_replace('?', '%s', $where[0]);
				$where  = vsprintf($format, $where[1]);
			}
		}
		
		if (!empty($this->data['condition'])) {
			//'预留WHERE', 'order', 'group', 'limit' …………等条件关键词处理接口
			$where = $where ? $where : "1 = 1";
			isset($this->data['condition']['where']) && $where .= ' AND ' . $this->data['condition']['where'];
			isset($this->data['condition']['group']) && $where .= ' GROUP BY ' . $this->data['condition']['group'];
			isset($this->data['condition']['order']) && $where .= ' ORDER BY ' . $this->data['condition']['order'];
			isset($this->data['condition']['limit']) && $where .= ' LIMIT ' . $this->data['condition']['limit'];
		}
		//清楚临时主键
		$where = empty($where) ? 'WHERE 1' : "WHERE {$where}";
		$this->condition = $where;
		return $this;
	}
	
	
	private function isSql($where) {
		if (!is_array($where) && in_array(strtolower(substr(trim($where), 0, 6)), array('select','update','delete','insert','replace'))) {
			return true;
		}
		return false;
	}

	//插入数据
	public function insert($data = array(), $replace = false) {
		if ($this->isSql($data)) {
			$sql = $data;
		} else {
			$fields = $this->implodefields($data);
			$insert = $replace ? 'REPLACE' : 'INSERT';
			$sql = "{$insert} INTO `{$this->db}`.`{$this->table()}` (" . implode(', ', $fields[1]) . ") values (" . implode(', ', $fields[2]) . ")";
		}
		$this->query($sql);
		return $this->getInsertId();
	}

	//插入数据
	public function addMore($fields, $data, $replace = false) {
		$fields = implode(', ', $fields);
		$values = array();
		foreach ($data as $value) {
			
			$values[] = "('" . implode("','", $value) . "')";
		}
		$valueStr = implode(',', $values);
		$insert = $replace ? 'REPLACE' : 'INSERT';
		$sql = "{$insert} INTO `{$this->db}`.`{$this->table()}` (" . $fields . ") values ".$valueStr;
		$this->query($sql);
		return $this->getInsertId();
	}

	public function add($data) {
		
	}

	public function save() {
		
	}
	//更新数据
	public function update($data = array(), $where = NULL) {
		$numargs = func_num_args();
		if ($numargs == 1) {
			$where = $data;
			$data = array();
		}
		if ($this->isSql($where)) {
			$sql = $where;
		} else {
			$fields = $this->implodefields($data);
			$this->condition($where);
			$sql = "UPDATE `{$this->db}`.`{$this->table()}` SET " . implode(', ', $fields[0]) . " {$this->condition}";
		}
		$this->query($sql);
		return $this->getAffectedRows();
	}

	//删除数据
	public function delete($where = NULL) {
		if ($this->isSql($where)) {
			$sql = $where;
		} else {
			$this->condition($where);
			$sql = "DELETE  FROM `{$this->db}`.`{$this->table()}` {$this->condition}";
		}
		$this->query($sql);
		return $this->getAffectedRows();
	}

	//查询数据
	public function select($where = NULL, $fields = '*') {
		if ($this->isSql($where)) {
			$sql = $where;
		} else {
			$this->condition($where);
			$sql = "SELECT {$fields} FROM `{$this->db}`.`{$this->table()}` {$this->condition}";
		}
		return $this->fetch($this->query($sql));
	}

	//查询一条数据  
	public function getOne($where, $fields = '*') {
		$data = $this->select($where, $fields = '*');
		if ($data) {
			return $data[0];
		}
		return array();
	}

	//查询多条数据  
	public function getAll($where, $fields = '*') {
		$data = $this->select($where, $fields = '*');
		return $data;
	}

	//结果数量  
	public function getCount($where = '', $fields = '*') {
		$this->condition($where);
		$sql = "SELECT count({$fields}) as count FROM `{$this->db}`.`{$this->table()}` {$this->condition}";
		$data = $this->query($sql);
		if ($data) {
			return @mysql_result($data, 0);
		}
		return 0;
	}

	//执行sql语句    
	public function query($sql, $flag = '0', $type = '') {
		$this->connect($sql);
		if ($this->config['dbDebug']) {
			$startime = $this->microtime_float();
		}

		//查询
		if ($type == 'UNBUFFERED' && function_exists('mysql_unbuffered_query')) {
			$result = @mysql_unbuffered_query($sql, $this->linkArr[self::$linkType]);
		} else {
			$result = @mysql_query($sql, $this->linkArr[self::$linkType]);
		}

		//重试
		if (in_array(mysql_errno($this->linkArr[self::$linkType]), array(2006, 2013)) && empty($result) && $this->config['dbPconnect'] == 0 && !defined('RETRY')) {
			define('RETRY', true);
			@mysql_close($this->linkArr[self::$linkType]);
			sleep(2);
			$result = $this->query($sql);
		}

		if ($result === false) {
			$this->errdie($sql);
		}

		if ($this->config['dbDebug']) {
			$endtime = $this->microtime_float();
			$this->sql[] = array(self::$linkType, $this->linkArr[self::$linkType], $sql, $endtime - $startime);
		}
		$this->clearTmp();
		return $flag == '0' ? $result : ($flag == '1' ? $this->getInsertId() : $this->getAffectedRows());
	}

	//返回结果$onlyone为true返回一条否则返回所有,$type有MYSQL_ASSOC,MYSQL_NUM,MYSQL_BOTH
	public function fetch($result, $onlyone = false, $type = MYSQL_ASSOC) {
		if ($result) {
			if ($onlyone) {
				$row = @mysql_fetch_array($result, $type);
				return $row;
			} else {
				$rowsRs = array();
				while ($row = @mysql_fetch_array($result, $type)) {
					$rowsRs[] = $row;
				}
				return $rowsRs;
			}
		}
		return array();
	}

	//可以运行SELECT，SHOW，EXPLAIN 或 DESCRIBE 等返回一个资源标识符的语句得到返回结果数组
	public function show($sql, $onlyone = false) {
		return $this->fetch($this->query($sql), $onlyone);
	}

	// 使用call函数处理同类型函数  
	public function __call($name, $arguments) {
		$callArr = array('on', 'where', 'order', 'between', 'group', 'limit', 'like', 'having');
		if (in_array($name, $callArr)) {
			$this->data['condition'][$name] = $arguments[0];
		} else {
			$this->errdie("function error: function {$name} is not in ($this->class) class exist");
		}
		return $this;
	}

	//返回最后一次插入ID
	public function getInsertId() {
		return @mysql_insert_id($this->linkArr[self::$linkType]);
	}

	//返回受影响行数
	public function getAffectedRows() {
		return @mysql_affected_rows($this->linkArr[self::$linkType]);
	}

	//获取错误信息
	private function error() {
		return (($this->linkArr[self::$linkType]) ? @mysql_error($this->linkArr[self::$linkType]) : @mysql_error());
	}

	//获取错误信息ID 
	private function errno() {
		return (($this->linkArr[self::$linkType]) ? @mysql_errno($this->linkArr[self::$linkType]) : @mysql_errno());
	}

	//获取版本信息
	public  function version() {
		if (empty($this->version)) {
			$this->version = mysql_get_server_info($this->linkArr[self::$linkType]);
		}
		return $this->version;
	}
	
	//清除临时数据
	private function clearTmp() {
		//清空操作数据
                $this->data = array();
		if ($this->server != '' || $this->tmpTable != '' || $this->tmpPrimaryKey != '') {
			$this->close($this->linkArr[self::$linkType]);
                	unset($this->linkArr[self::$linkType]);
                	self::$linkType = '';
		}
                $this->server = '';
                $this->tmpTable = '';
                $this->tmpPrimaryKey = '';
		return '';
	}	

	//清空连接池
	public  function close() {
		foreach ($this->linkArr as $value) {
			mysql_close($value);
		}
		$this->linkArr = array();
	}
	
	//关闭数据库
	public  function closeLink($link) {
		mysql_close($link);
	}
	public  function filter($data) {
		if (is_array($data)) {
			foreach ($data as $key => $value) {
				$data[$key] = $this->filter($value);
			}
		}
		return mysql_escape_string($data);
	}
	//打印错误信息
	private function errdie($sql = '') {
		if ($this->config['dbDebug']) {
			die('<B>MySQL ERROR</B></BR>
				 db:' . self::$linkType . '</BR>
				 SQL:' . $sql . '</BR>
				 ERRNO:' . $this->errno() . '</BR> 
				 ERROR:' . $this->error() . '</BR>');
		}
		die('DB ERROR！！！');
	}

	//获取时间微妙数
	private function microtime_float() {
		list($usec, $sec) = explode(" ", microtime());
		return ((float) $usec + (float) $sec);
	}

	//析构函数
	public function __destruct() {
		if ($this->config['dbDebug']) {
			echo '<hr><pre>';
			print_r($this->sql);
			echo '</pre>';
		}
		$this->close();
	}

}
